#include "SDLRenderer.h"
#include <GameObject/Components.h>
#include <Log/Log.h>
#include <Renderer/SDLRenderer/SDLTexture.h>

namespace Engine2D
{
    std::shared_ptr<Renderer> Renderer::Instance()
    {
        if (!s_renderer) {
            s_renderer = std::make_shared<SDLRenderer>();
        }
        return s_renderer;
    }

    SDLRenderer::SDLRenderer()
        : m_renderer(nullptr)
    {
    }

    SDLRenderer::~SDLRenderer()
    {
        if (m_renderer) {
            SDL_DestroyRenderer(m_renderer);
        }
        // LOG_INFO("Destroy Renderer");
    }

    void SDLRenderer::SetWindow(void * wind)
    {
        m_renderer = SDL_CreateRenderer((SDL_Window*)wind, -1, 0);
        if (!m_renderer) {
            LOG_ERROR("{}", SDL_GetError());
            exit(-1);
        }
        LOG_INFO("Create Renderer");
    }
    
    void SDLRenderer::Clear(int r, int g, int b, int a)
    {
        SDL_SetRenderDrawColor(m_renderer, r, g, b, a);
        SDL_RenderClear(m_renderer);
    }
    
    void SDLRenderer::Render()
    {
        SDL_RenderPresent(m_renderer);
    }
    
    void SDLRenderer::DrawPolygon(std::vector<Vertex> & vertex, std::vector<int> & indices)
    {
        if (!m_camera.expired()) {
            for (auto && vtx : vertex) {
                vtx.pos = m_camera.lock()->GetComponent<TransformComponent>().lock()->Transform() * vtx.pos;
            }
        }
        SDL_Vertex * vertices = (SDL_Vertex*)alloca(sizeof(SDL_Vertex) * vertex.size());
        for (size_t i = 0; i < vertex.size(); ++i) {
            vertices[i] = SDL_Vertex{
                SDL_FPoint{vertex[i].pos.x, vertex[i].pos.y},
                SDL_Color{(Uint8)vertex[i].color.x, (Uint8)vertex[i].color.y, (Uint8)vertex[i].color.z, (Uint8)vertex[i].color.w}
            };
        }
        SDL_RenderGeometry(m_renderer, nullptr, vertices, (int)vertex.size(), indices.size() ? indices.data() : nullptr, (int)indices.size());
    }

    void SDLRenderer::DrawTexture(std::shared_ptr<Texture> texture, std::optional<SLua_Rect> & src, std::optional<SLua_Rect> & dst)
    {
        SDL_Rect srcRect = src ? SDL_Rect{src->x, src->y, src->width, src->height} : SDL_Rect{};
        SDL_Rect dstRect = dst ? SDL_Rect{dst->x, dst->y, dst->width, dst->height} : SDL_Rect{};
        SDL_RenderCopy(m_renderer, std::dynamic_pointer_cast<SDLTexture>(texture)->GetSDLTexture(),
            src ? &srcRect : nullptr,
            dst ? &dstRect : nullptr
        );
    }

} // namespace Engine2D
